#include <tchar.h>

#include "D3d12GraphicsManager.hpp"
#include "MemoryManager.hpp" 

#include "WindowsApplication.hpp"

using namespace My;

namespace My
{
    GfxConfiguration config(8, 8, 8, 8, 32, 0, 0, 960, 540, L"Game Engine From Scratch (Windows)");
    IApplication* g_pApp = static_cast<IApplication*>(new WindowsApplication(config));
    MemoryManager*	g_pMemoryManager= static_cast<MemoryManager*>(new MemoryManager);
    GraphicsManager* g_pGraphicsManager = static_cast<GraphicsManager*>(new D3d12GraphicsManager);
}

int My::WindowsApplication::Initialize()
{
    int result;

    // 基类初始化
    result = BaseApplication::Initialize();

    if(0 != result) exit(result);   // 异常退出程序

    // 从控制台程序获取HINSTANCE
    HINSTANCE hInstance = GetModuleHandle(NULL);

    // 此结构保存窗口类的信息
    WNDCLASSEX wc;
    {
        // 清除窗口类以供使用
		ZeroMemory(&wc, sizeof(WNDCLASSEX));

        // 在结构中填写所需信息
		wc.cbSize = sizeof(WNDCLASSEX);
		wc.style = CS_HREDRAW | CS_VREDRAW;
		wc.lpfnWndProc = WindowProc;
		wc.hInstance = hInstance;
		wc.hCursor = LoadCursor(NULL, IDC_ARROW);
		wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
		wc.lpszClassName = _T("GameEngineFromScratch");

		// 注册窗口类
		RegisterClassEx(&wc);
    }

    // 创建窗口，并使用返回的结构作为句柄
    HWND hWnd = CreateWindowExW(
        0,
        L"GameEngineFromScratch",       // 窗口类名
        m_Config.appName,               // 窗口标题
        WS_OVERLAPPEDWINDOW,            // 窗口风格
        CW_USEDEFAULT,                  // 窗口x位置
        CW_USEDEFAULT,                  // 窗口y位置
        m_Config.screenWidth,           // 窗口宽度
        m_Config.screenHeight,          // 窗口高度
        NULL,                           // 没有父窗口，NULL
        NULL,                           // 没有使用菜单，NULL
        hInstance,                      // 应用程序句柄，NULL
        NULL);                          // 用于多窗口，NULL

    // 在屏幕中显示窗口
    ShowWindow(hWnd, SW_SHOW);

    m_hWnd = hWnd;

    return result;
}

void My::WindowsApplication::Finalize()
{
}

void My::WindowsApplication::Tick()
{
	// 此结构保存Windows事件消息
    MSG msg;

	// 我们在这里使用PeekMessage而不是GetMessage
    // 因为我们不应该在引擎执行驱动程序模块以外的任何地方阻塞线程
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        // 将击键(keystroke)消息翻译成正确的格式
        TranslateMessage(&msg);

        // 发送消息给WindowProc函数
        DispatchMessage(&msg);
    }
}

// 程序的主要消息处理器
LRESULT My::WindowsApplication::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    // 对给定的消息进行排序并找到要运行的代码
    switch (message)
    {
    case WM_PAINT:      // 我们将用渲染模块替换此部分
	{        
        break;
    }

    case WM_DESTROY:     // 当窗口关闭时，将读取此消息
    {       
        // 关闭程序
        PostQuitMessage(0);
        BaseApplication::m_bQuit = true;
        return 0;
    }
    }

    // 处理switch语句未处理的消息
    return DefWindowProc(hWnd, message, wParam, lParam);
}
